package com.qf.commons.redis.aspest;

import com.qf.commons.core.utils.SpelUtils;
import com.qf.commons.redis.annotation.RLocks;
import com.qf.commons.redis.utils.RsLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 分布式锁的切面
 * author Ken
 * create_time 2022/11/15
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class RsLockAspest {


    /**
     * 加锁的环绕增强
     * execution(* com.qf.business.**.*Controller.*(..))
     * @annotation(xxx.xxx.xxx.X)
     * @within(xxx.xxx.xxx.Y)
     *
     * @return
     */
    @Around("@annotation(com.qf.commons.redis.annotation.RLocks)")
    public Object lockAspect(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            //Aop中获取方法的注解
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
            RLocks rLocks = method.getAnnotation(RLocks.class);

            //获取spel表达式
            //'mylock_' + #entity.name -> Map<entity -> Object(name -> zhangsan)>  -> mylock_zhangsan
            //方法形参（形参的名字 -> 形参的值） -> 容器 + spel -> Spring表达式解析器 -> mylock_zhangsan
            String spel = rLocks.key();
            log.debug("[cluster lock] 获取锁的key - {}", spel);

            //解析spel表达式为真正的key
            String key = SpelUtils.spelParse(spel, method, joinPoint.getArgs());
            log.debug("[cluster lock] spel表达式解析后的结果 - {}", key);

            //加锁
            RsLock.lock(key);

            //放行
            result = joinPoint.proceed();
        } finally {
            //解锁
            RsLock.unlock();
        }
        return result;
    }
}
